package com.uduemc.biso.node.web.utils;

import java.io.IOException;
import java.io.StringWriter;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;

import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.VelocityEngine;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.mail.javamail.JavaMailSender;
import org.springframework.mail.javamail.MimeMessageHelper;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;

import com.uduemc.biso.node.core.entities.SEmail;
import com.uduemc.biso.node.core.property.GlobalProperties;
import com.uduemc.biso.node.web.service.byfeign.EmailService;

@Component
public class EmailUtil {

	private final Logger logger = LoggerFactory.getLogger(getClass());

	@Autowired
	private JavaMailSender mailSender;

	@Autowired
	private EmailService emailService;

	@Autowired
	private GlobalProperties globalProperties;

	private static VelocityEngine velocityEngine;

	public static String MAIL_FROM;

	public final static String MAIL_TYPE_FORM_EMAIL = "form_email";

	private final static String MAIL_TEMPLATE_FORM_EMAIL = "templates/email/form/email.vm";

	public static void addMailQueue(List<SEmail> emailList) {
		if (emailList == null || emailList.size() == 0) {
			return;
		}
		for (SEmail sEmail : emailList) {
			addMailQueue(sEmail);
		}
	}

	public static void addMailQueue(SEmail sEmail) {
		if (null == sEmail || sEmail.getId() == 0) {
			return;
		}
		MailQueue.put(sEmail);
	}

	@Async("emailThreadPool")
	public void startSendMailThread() {
		logger.info("启动邮件发送线程: " + Thread.currentThread().getName());
		while (true) {
			try {
				SEmail sEmail = MailQueue.take();
				if (sEmail == null) {
					continue;
				}
				sendMail(sEmail);
			} catch (Exception e) {
				logger.error("进程错误！", e);
			}
		}
	}

	private void sendMail(SEmail sEmail) {
		try {
			MimeMessageHelper messageHelper = new MimeMessageHelper(mailSender.createMimeMessage());
			messageHelper.setFrom(globalProperties.getSite().getMailFromname() + '<' + MAIL_FROM + '>');
			messageHelper.setTo(sEmail.getMailTo());
			messageHelper.setSubject(sEmail.getMailSubject());
			messageHelper.setText(sEmail.getMailBody(), true);

			mailSender.send(messageHelper.getMimeMessage());

			logger.info("发送邮件成功 mailId:" + sEmail.getId());
			sEmail.setSendAt(new Date());
			sEmail.setSend(1);
		} catch (Exception e) {
			sEmail.setSendError(e.getMessage());
			sEmail.setSend(2);

			logger.error("发送邮件失败", e);
		}

		try {
			emailService.update(sEmail);
		} catch (IOException e) {
			logger.error("更新邮件状态失败", e);
		}
	}

	public static String generateFormMailBody(Map<String, Object> mapData) {
		StringWriter stringWriter = new StringWriter();
		Template template = velocityEngine.getTemplate(MAIL_TEMPLATE_FORM_EMAIL);

		template.merge(new VelocityContext(mapData), stringWriter);

		return stringWriter.toString();
	}

	public static final class MailQueue {

		private final static Logger logger = LoggerFactory.getLogger(MailQueue.class);

		private static BlockingQueue<SEmail> mailQueue = new LinkedBlockingQueue<>();

		public static boolean mailQueueContains(SEmail sEmail) {
			for (SEmail mailQueueSEmail : mailQueue) {
				if (mailQueueSEmail.getId().longValue() == sEmail.getId().longValue()) {
					return true;
				}
			}
			return false;
		}

		public static void put(SEmail sEmail) {
			try {
				if (mailQueueContains(sEmail)) {
					return;
				}
				mailQueue.put(sEmail);
			} catch (InterruptedException e) {
				logger.error("添加待发到邮件到队列失败", e);
			}
		}

		public static SEmail take() {
			try {
				return mailQueue.take();
			} catch (InterruptedException e) {
				logger.error("从队列取得待发邮件失败", e);
				return null;
			}
		}

		public static int getQueueSize() {
			return mailQueue.size();
		}
	}

	@Autowired
	public void setVelocityEngine(VelocityEngine velocityEngine) {
		EmailUtil.velocityEngine = velocityEngine;
	}

	@Value("${spring.mail.username}")
	public void setMailFrom(String mailFrom) {
		EmailUtil.MAIL_FROM = mailFrom;
	}

}